#!/usr/bin/env python3
"""
setuptools.setup() 函数全面介绍
详细说明函数签名、参数、使用方法和最佳实践
"""

def introduction():
    """setuptools.setup() 函数介绍"""
    
    print("📚 setuptools.setup() 函数全面介绍")
    print("=" * 60)
    
    print("""
setuptools.setup() 是 Python 包构建和分发的核心函数。
它是 distutils.setup() 的增强版本，提供了更多功能和更好的扩展性。

基本作用：
✓ 定义包的元数据 (名称、版本、作者等)
✓ 指定包的结构 (哪些模块、包含哪些文件)
✓ 声明依赖关系 (install_requires, extras_require)
✓ 配置构建过程 (C 扩展、自定义命令)
✓ 设置入口点 (console_scripts, gui_scripts)
    """)

def show_function_signature():
    """展示函数签名"""
    
    print("\n🔧 函数签名和导入:")
    print("-" * 30)
    
    signature_code = '''
from setuptools import setup

def setup(
    name=None,                    # 包名
    version=None,                 # 版本号
    description=None,             # 简短描述
    long_description=None,        # 详细描述
    long_description_content_type=None,  # 描述格式
    url=None,                     # 项目主页
    download_url=None,            # 下载地址
    project_urls=None,            # 相关链接
    
    author=None,                  # 作者
    author_email=None,            # 作者邮箱
    maintainer=None,              # 维护者
    maintainer_email=None,        # 维护者邮箱
    
    license=None,                 # 许可证
    classifiers=None,             # PyPI 分类器
    keywords=None,                # 关键词
    
    packages=None,                # Python 包列表
    py_modules=None,              # Python 模块列表
    package_dir=None,             # 包目录映射
    package_data=None,            # 包数据文件
    include_package_data=None,    # 是否包含 MANIFEST.in
    exclude_package_data=None,    # 排除的包数据
    data_files=None,              # 数据文件
    
    install_requires=None,        # 运行时依赖
    extras_require=None,          # 可选依赖
    python_requires=None,         # Python 版本要求
    setup_requires=None,          # 构建时依赖 (已废弃)
    
    entry_points=None,            # 入口点
    console_scripts=None,         # 控制台脚本 (已废弃)
    gui_scripts=None,             # GUI 脚本 (已废弃)
    scripts=None,                 # 脚本文件
    
    ext_modules=None,             # C 扩展模块
    ext_package=None,             # 扩展包名
    cmdclass=None,                # 自定义命令类
    
    zip_safe=None,                # 是否可以从 zip 运行
    platforms=None,               # 支持的平台
    
    **kwargs                      # 其他参数
):
    """setuptools 的主要构建函数"""
    pass
    '''
    
    print(signature_code)

def explain_key_parameters():
    """解释关键参数"""
    
    print("\n📋 关键参数详解:")
    print("-" * 25)
    
    params = {
        "基本元数据": {
            "name": "包名，必须唯一，将作为 PyPI 上的包名",
            "version": "版本号，推荐使用语义化版本 (如 1.2.3)",
            "description": "一行简短描述，显示在 PyPI 搜索结果中",
            "long_description": "详细描述，通常是 README 内容",
            "author": "作者姓名",
            "author_email": "作者邮箱",
            "license": "许可证，如 'MIT', 'Apache-2.0'",
            "url": "项目主页 URL"
        },
        
        "包结构": {
            "packages": "要包含的 Python 包列表，可用 find_packages() 自动发现",
            "py_modules": "单独的 Python 模块文件列表",
            "package_dir": "包目录映射，如 {'': 'src'}",
            "package_data": "包内数据文件，如 {'pkg': ['data/*.txt']}",
            "include_package_data": "是否包含 MANIFEST.in 中指定的文件"
        },
        
        "依赖管理": {
            "install_requires": "运行时依赖列表，如 ['requests>=2.0', 'numpy']",
            "extras_require": "可选依赖，如 {'dev': ['pytest'], 'docs': ['sphinx']}",
            "python_requires": "支持的 Python 版本，如 '>=3.8'",
            "setup_requires": "构建时依赖 (已废弃，用 pyproject.toml)"
        },
        
        "入口点": {
            "entry_points": "入口点配置，如控制台命令、插件接口",
            "console_scripts": "控制台脚本 (已废弃，用 entry_points)",
            "scripts": "脚本文件列表"
        },
        
        "扩展构建": {
            "ext_modules": "C/C++ 扩展模块列表",
            "cmdclass": "自定义构建命令类，如 {'build_ext': CMakeBuild}"
        },
        
        "分类和标记": {
            "classifiers": "PyPI 分类器，描述包的特性、许可证、Python 版本等",
            "keywords": "关键词列表，帮助搜索发现",
            "platforms": "支持的平台"
        }
    }
    
    for category, param_dict in params.items():
        print(f"\n🔸 {category}:")
        for param, desc in param_dict.items():
            print(f"   {param:20} - {desc}")

def show_practical_examples():
    """展示实际使用示例"""
    
    print(f"\n💼 实际使用示例:")
    print("-" * 25)
    
    print("\n1️⃣  基础 Python 包:")
    print("-" * 20)
    
    basic_example = '''
from setuptools import setup, find_packages

setup(
    name="my-awesome-package",
    version="1.0.0",
    description="一个很棒的 Python 包",
    long_description=open("README.md").read(),
    long_description_content_type="text/markdown",
    
    author="张三",
    author_email="zhangsan@example.com",
    url="https://github.com/zhangsan/my-awesome-package",
    
    packages=find_packages(),
    python_requires=">=3.8",
    install_requires=[
        "requests>=2.25.0",
        "click>=8.0.0",
    ],
    
    entry_points={
        "console_scripts": [
            "myapp=my_package.cli:main",
        ],
    },
    
    classifiers=[
        "Development Status :: 4 - Beta",
        "Intended Audience :: Developers",
        "License :: OSI Approved :: MIT License",
        "Programming Language :: Python :: 3.8",
        "Programming Language :: Python :: 3.9",
        "Programming Language :: Python :: 3.10",
    ],
)
    '''
    print(basic_example)
    
    print("\n2️⃣  包含 C 扩展的包 (你的情况):")
    print("-" * 35)
    
    extension_example = '''
from setuptools import setup, find_packages, Extension
from setuptools.command.build_ext import build_ext

class CMakeExtension(Extension):
    def __init__(self, name, sourcedir=''):
        Extension.__init__(self, name, sources=[])
        self.sourcedir = os.path.abspath(sourcedir)

class CMakeBuild(build_ext):
    # ... CMake 构建逻辑

setup(
    name="my-package-with-cpp",
    version="1.0.0",
    description="包含 C++ 扩展的 Python 包",
    
    packages=find_packages(),
    
    # C++ 扩展配置
    ext_modules=[
        CMakeExtension('my_package.c_module.my_c_string', 'my_package/c_module')
    ],
    cmdclass={'build_ext': CMakeBuild},
    
    install_requires=[
        "numpy>=1.20.0",
    ],
    
    # 构建时依赖 (在 pyproject.toml 中指定更好)
    zip_safe=False,  # 包含 C 扩展时通常设为 False
)
    '''
    print(extension_example)
    
    print("\n3️⃣  现代混合配置 (推荐方式):")
    print("-" * 30)
    
    modern_example = '''
# pyproject.toml 中的静态元数据
[project]
name = "my-modern-package"
version = "1.0.0"
description = "现代 Python 包"
authors = [{name = "张三", email = "zhangsan@example.com"}]
dependencies = ["requests>=2.25.0"]

[build-system]
requires = ["setuptools>=64", "wheel", "cmake>=3.12"]
build-backend = "setuptools.build_meta"

# setup.py 中只配置动态部分 (C 扩展)
from setuptools import setup

def has_pyproject_toml():
    return os.path.exists('pyproject.toml')

if has_pyproject_toml():
    # 最小配置，元数据来自 pyproject.toml
    setup(
        ext_modules=[CMakeExtension(...)],
        cmdclass={'build_ext': CMakeBuild},
    )
else:
    # 完整配置，向后兼容
    setup(
        name="my-modern-package",
        version="1.0.0",
        # ... 完整配置
    )
    '''
    print(modern_example)

def explain_modern_usage():
    """解释现代用法"""
    
    print(f"\n🚀 现代最佳实践:")
    print("-" * 25)
    
    print("""
现代 Python 包开发推荐的配置方式：

1️⃣  静态元数据 → pyproject.toml
   ✓ 包名、版本、描述、作者等
   ✓ 依赖关系
   ✓ 入口点
   ✓ 分类器

2️⃣  动态配置 → setup.py
   ✓ C/C++ 扩展模块
   ✓ 自定义构建命令
   ✓ 复杂的包发现逻辑
   ✓ 需要运行时计算的配置

3️⃣  构建系统 → pyproject.toml [build-system]
   ✓ 构建后端 (setuptools.build_meta)
   ✓ 构建依赖 (setuptools, wheel, cmake)

优势：
✓ 标准化配置格式
✓ 更好的工具支持
✓ 元数据和构建逻辑分离
✓ 更容易验证和解析
    """)

def show_command_integration():
    """展示与命令系统的集成"""
    
    print(f"\n⚙️  setup() 与命令系统的集成:")
    print("-" * 35)
    
    print("""
setup() 函数不只是声明配置，它还：

1️⃣  解析命令行参数 (sys.argv)
2️⃣  创建 Distribution 对象
3️⃣  根据命令执行相应操作：

   python setup.py egg_info
   ├─ setup() 被调用
   ├─ 创建 egg_info 命令对象
   ├─ 读取配置中的元数据
   └─ 生成 .egg-info 目录

   python setup.py build_ext
   ├─ setup() 被调用  
   ├─ 检测到 ext_modules 配置
   ├─ 使用 cmdclass 中的 CMakeBuild
   └─ 编译 C++ 扩展

   python setup.py bdist_wheel
   ├─ setup() 被调用
   ├─ 执行必要的构建步骤
   └─ 创建 .whl 文件

现代 PEP 517 环境中：
✓ pip 通过 setuptools.build_meta 调用
✓ build_meta 内部调用 setup()
✓ setup() 根据传入的命令执行相应逻辑
    """)

def common_pitfalls():
    """常见问题和陷阱"""
    
    print(f"\n⚠️  常见问题和陷阱:")
    print("-" * 25)
    
    pitfalls = [
        ("重复调用", "不要在同一进程中多次调用 setup()", "setup() 会修改全局状态"),
        
        ("动态导入", "避免在 setup.py 中导入待构建的包", "包可能还未构建完成"),
        
        ("路径问题", "使用相对于 setup.py 的路径", "构建时工作目录可能不同"),
        
        ("版本管理", "不要硬编码版本号", "使用动态版本或 __version__"),
        
        ("依赖冲突", "明确指定依赖版本范围", "避免版本冲突"),
        
        ("setup_requires", "不要使用 setup_requires", "已废弃，用 pyproject.toml"),
        
        ("命令检查", "不要检查 'build'/'install' 命令", "现代构建系统使用细分命令"),
    ]
    
    for issue, problem, solution in pitfalls:
        print(f"\n❌ {issue}:")
        print(f"   问题: {problem}")
        print(f"   解决: {solution}")

def main():
    introduction()
    show_function_signature()
    explain_key_parameters()
    show_practical_examples()
    explain_modern_usage()
    show_command_integration()
    common_pitfalls()
    
    print(f"\n" + "=" * 60)
    print("📖 总结:")
    print("   setuptools.setup() 是 Python 包构建的核心函数")
    print("   现代开发推荐 pyproject.toml + setup.py 混合配置")
    print("   主要用于声明包信息和构建配置")
    print("   在 PEP 517 环境中通过构建后端间接调用")
    print("=" * 60)

if __name__ == "__main__":
    main() 